/*  REVIEWED_FOR_64BIT=YES  */
//
// Copyright (C) 1991, All Rights Reserved, by
// Digital Equipment Corporation, Maynard, Mass.
//
// This software is furnished under a license and may be used and copied
// only  in  accordance  with  the  terms  of such  license and with the
// inclusion of the above copyright notice. This software or  any  other
// copies thereof may not be provided or otherwise made available to any
// other person. No title to and ownership of  the  software  is  hereby
// transferred.
//
// The information in this software is subject to change without  notice
// and  should  not be  construed  as  a commitment by Digital Equipment
// Corporation.
//
// Digital assumes no responsibility for the use or  reliability  of its
// software on equipment which is not supplied by Digital.
//

//
//  FACILITY:
//
//	Calaveras Thread Synchronization Services
//	(aka Sthread Locking or SLock)
//
//  ABSTRACT:
//
//	External definitions for Lock services
//
//  AUTHORS:
//
//	Steve Glaser
//
//      MP Design: JP Bono
//
//  CREATION DATE:
//
//	10 September 1991
//
//  MODIFICATION HISTORY:
//
// 	RCS Log Removed.  To view log, use: rlog <file>


#ifndef _SLOCK_HXX_
#define _SLOCK_HXX_

#ifdef __SADE__

#include "csx_ext_p_dsh_os_slock.hxx"
#include "sade_os_misc.h"

#include "sade_os_slock.hxx"

#ifndef _BASICTYPES_H_
#include <basictypes.h>
#endif
#ifndef _DQUEUE_HXX_
#include <dqueue.hxx>
#endif
#ifndef _STDIO_H_
#include <stdio.h>
#endif
#ifndef _STDLIB_H_
#include <stdlib.h>
#endif
#ifndef _ATOMIC_H_
#include <atomic.h>
#endif

#define Sthread_MutexSimpleSpl Sthread_MutexSpl
#define Sthread_MutexSimpleSpl_unconstructed Sthread_MutexSpl_unconstructed

#else /* __SADE__ */

#if !defined(lint) && defined(INCLUDE_ALL_RCSID)
/* $Header: /usr/local/cvs/archive/Dart/server/src/kernel/min_kernel/include/slock.hxx,v 11.14.4.16 2012/02/04 01:03:14 zhaow2 Exp $ */
#endif

#ifndef _CALAVERS_H_
#include <calavers.h>
#endif

#ifndef _BOOLEAN_H_
#include <boolean.h>
#endif

#ifndef _BASICTYPES_H_
#include <basictypes.h>
#endif

#ifndef _TYPES_H_
#include <types.h>
#endif

#ifndef _M_PERCPU_HXX_
#include <m_percpu.hxx>
#endif


#if defined(DEBUG_ALL) && !defined(Sthread_DEBUG)
#define Sthread_DEBUG
#endif

#if defined(Sthread_DEBUG) && !defined(_DEBUG_H_)
#include <debug.h>
#endif

#if defined(Sthread_DEBUG) && !defined(Sthread_assert)
#define Sthread_assert(x) (void) (Sthread_Verify && (assert(x), 0))
#endif

#ifdef Sthread_assert
#include <assert.h>
#endif

#ifndef Sthread_assert
#define Sthread_assert(ignore) ((void)0)
#endif

#ifndef _SPINLOCK_HXX_
#include <spinlock.hxx>
#endif

#include <mp.hxx>
#include <i_lm_lstat_def.hxx>

#ifdef Sthread_INLINE

extern boolean_t Sthread_isUnlockedRT();
extern boolean_t Sthread_isLockedRT();

#else // Sthread_INLINE

# ifdef Sthread_FORCE_INLINE
#  define Sthread_INLINE 
# else
#  define Sthread_INLINE inline
# endif

#ifdef Blackbird_Schedule
extern unsigned int can_run_rt[];
#endif

//
// Define enough of sthread.hxx to get around chicken and egg problems
//
// All we require is that there be a class named Sthread and a
// set of queue manipluation routines for them.
//
// We don't need #ifndef _STHREAD_HXX_ / #endif around this cause
// sthread.hxx includes us.  The following will be defined once
// whether or not Sthread was explicitly included in the .cxx file.
//


//
// Debugging support
//


// This variable is set non-zero to cause assertions to be checked.
// 
extern boolean_t Sthread_Verify;


// The following routines are for use in assertions throughout the system.
// Note that they always return TRUE if Sthread_DEBUG is not defined.
//

extern boolean_t Sthread_AssertCanBlock();
// Returns FALSE if calling code is not allowed to block

extern boolean_t Sthread_AssertCannotBlock();
// Returns FALSE if calling code is allowed to block


//
//  Supporting classes
//

class Sthread_MutexStats {
  public:
    volatile ulong32 heldCount;
    volatile ulong32 lockCount;
    volatile ulong32 tryCount;
    Sthread_MutexStats();
#if defined(Sthread_DEBUG) || defined(Sthread_RECORD_STATS)
    void recordTry() { tryCount++; heldCount++; }    
    void recordLock() { lockCount++; heldCount++; }
    void recordUnlock() { heldCount--; }
#else
    void recordTry() { /* do nothing */ }
    void recordLock() { /* do nothing */ }
    void recordUnlock() { /* do nothing */ }
#endif
};


// 
// Three kinds of Mutexs are used in Calaveras.  Which Mutex is used for a
// particular application is a function of which levels of the system need
// to access the data being protected.
// 
// A true object oriented system would provide these as derived classes from
// a base Mutex class.  Due to performance considerations, this has not been
// done.  The polymorphism provided is explicitly coded, thus avoiding
// virtual function calls and allowing inline implementation of many common
// cases.
// 
// MutexSplHigh should be used to protect data that will be accessed at
// interrupt level.  Any level can lock a MutexSplHigh.  Other Mutexes may be
// held prior to obtaining a MutexSplHigh.  Other mutex may be obtained while a
// MutexSplHigh is held provided that the *High varients of the locking
// primitives are used.  Interrupts are off while a MutexSplHigh is locked.
// 
// MutexRT should be used to protect data that will be accessed at real-time
// and thread levels (but not at interrupt level).  Other Mutexes may be
// held prior to obtaining a MutexRT.  Other MutexRT and MutexSplHigh locks may
// be obtained while a MutexRT is held.  A Mutex may be obtained through the
// tryLock.  Interrupt level code may conditionally ask for a MutexRT using
// a tryLockHigh.  Context switches are disabled whle a MutexRT is locked.
// Thread level code must obey the rules for real-time code while it holds a
// MutexRT.
// 
// Mutex should be used to protect data that will be accessed only at thread
// level.  This is the only Mutex that can block.  All other Mutex styles
// either return success immediately (uniprocessor case) or spin waiting for
// the lock to be available (multiprocessor case).  Other Mutex, MutexRT and
// MutexSplHigh locks may be obtained while a Mutex is held.  No MutexRT or
// MutexSplHigh locks may be held prior to obtaining a Mutex. No deadlock
// detection or prevention support is provided.
//
//					Mutex kind
//			+---------------+---------------+---------------+
// Processing Level:	|  MutexSplHigh	|    MutexRT	| Mutex (plain)	|
//                  	+---------------+---------------+---------------+
// 			| lockHigh	|		|		|
// 			| unlockHigh	|		|		|
//           interrupt	| trylockHigh   |     none	|     none	|
//			| lockSlow	|		|		|
//			| unlockSlow	|		|		|
//			+---------------+---------------+---------------+
//			| lock		| lock		|		|
//			| unlock	| unlock	|		|
//    real-time domain	| trylock	| trylock	|     none	|
//			| lockSlow	| 		|		|
//			| unlockSlow	| 		|		|
//			+---------------+---------------+---------------+
//			| lock		| lock		| lock		|
//        		| unlock	| unlock	| unlock	|
//	  thread level	| tryLock	| tryLock	| tryLock	|
//        		| lockSlow	| 		| 		|
//        		| unlockSlow	| 		| 		|
//			+---------------+---------------+---------------+
//
//

//
// Calaveras uses three varieties of locks (aka Mutexes).
//
// They are very similar, and in the absence of other considerations would
// be implemented using inheritance from a common base class.  Due to
// performance constraints and a requirement to work early in the boot
// process, before static constructors, the polymorphism has been
// implemented statically in the few places where there is a difference.
//
//
// Notes:
//
// You must call the primitive appropriate to your current operating level.
//
// No deadlock detection or prevention support is provided.
//
#ifdef Sthread_DEBUG
#ifndef NULL
#define NULL    0
#endif /*       NULL */
#endif


class Sthread_MutexSpl_unconstructed {
private:
    Spinlock_unconstructed spl;
#ifdef Sthread_DEBUG
    int	     data;
    Sthread  *owner;
    ulong64  ticks_SplStart;
#endif
public:
#ifdef Sthread_DEBUG
    void initialize() { spl.initialize(); data = 0; owner = (Sthread*)NULL; ticks_SplStart = 0; }
#else
    void initialize() { spl.initialize(); }
#endif
    void lock();                // Lock the Mutex, delaying the thread if
                                // necessary.  Callable from real-time and
                                // thread levels ONLY.

    void unlock();              // Unlock the Mutex, allowing any blocked
                                // threads to continue.  Callable from
                                // real-time and thread levels ONLY.

    void unlockHigh();          // Unlock the Mutex, allowing any blocked
                                // threads to continue, callable from
                                // interrupt level ONLY

    boolean_t tryLock();        // Grab the lock if it is available.  Return
                                // TRUE if the lock was grabbed, FALSE
                                // otherwise.  This primitive will not
                                // block. Callable from real-time and thread
                                // levels ONLY.

    boolean_t tryLockHigh();    // Grab the lock if it is available.  Return
                                // TRUE if the lock was grabbed, FALSE
                                // otherwise.  This primitive will not block
                                // callable from interrupt level ONLY

#ifdef Sthread_DEBUG
    Sthread *locker() const;	// Returns pointer to thread holding
				// this lock if known, or NULL if lock
				// not held or the locker is not known
#endif

    boolean_t assertLocked() const;
    				// return FALSE if the mutex is known
				// to be unlocked.  return TRUE if the
				// mutex is locked or if the lock
				// state is not known.

    boolean_t assertUnlocked() const;
    				// return FALSE if the mutex is known
				// to be locked.  return TRUE if the
				// mutex is not locked or if the lock
				// state is not known.

#ifdef Sthread_DEBUG
    boolean_t MutexSplHoldingTimeReasonable(ulong64 msHoldingTimeLimit,
                                            ulong64 msHoldingTime);
#endif
};

/*
 * Sthread_MutexSimpleSpl_unconstructed
 *
 * a simple spin lock Mutex for use where locks are not
 * contended but are used heavily or in critical code paths
 *
 * use lockstats to confirm the correct usage
 */

class Sthread_MutexSimpleSpl_unconstructed
{
private:
    unsigned _lock;

public:
    
    void lock()
    {
        splCount_inc();
        if (mp_atomic_compare_and_swap_32(0, 1, &_lock)) 
        {
            lockContended();
        }
    }

    void unlock()
    {
        _lock = 0;
        splCount_dec();
    }


    void initialize(){ _lock = 0; }
    void destroy() {/* do nothing - put here to satisfy SADE */ }
protected:
    void lockContended();
};

/*
 * Sthread_MutexSimpleSpl
 *
 * a simple spin lock Mutex for use where locks are not
 * contended but are used heavily or in critical code paths
 *
 * use lockstats to confirm the correct usage
 */

class Sthread_MutexSimpleSpl : public Sthread_MutexSimpleSpl_unconstructed
{
public:
    Sthread_MutexSimpleSpl() 
    {
        Sthread_MutexSimpleSpl_unconstructed::initialize();
    }

    ~Sthread_MutexSimpleSpl() 
    {
        Sthread_MutexSimpleSpl_unconstructed::destroy();
    }
protected:
    void initialize();
    void destroy();
    
};


class Sthread_MutexSpl : public Sthread_MutexSpl_unconstructed {
private:
//	void initialize(); HASSEY temp workaround for Rhea build issue
public:
    Sthread_MutexSpl() { 
		Sthread_MutexSpl_unconstructed::initialize();
	}
};

//
// Special version of Sthread_MutexSpl that allows a given thread to acquire
// the same lock more than once (recursively).
//
class Sthread_MutexSpl_r {

  private:

    Spinlock_r_unconstructed spl;
#ifdef Sthread_DEBUG
    int	     data;
    Sthread  *owner;
#endif

  public:

#ifdef Sthread_DEBUG
    Sthread_MutexSpl_r() { spl.initialize(); data = 0; owner = (Sthread*)NULL; }
#else
    Sthread_MutexSpl_r() { spl.initialize(); }
#endif

    ~Sthread_MutexSpl_r() { assertUnlocked(); }

    void lock_r();              // Lock the Mutex recursively, delaying the
				// thread if necessary.  Callable from
				// real-time and thread levels ONLY.

    void unlock_r();            // Unlock the Mutex recursively, allowing
				// any blocked threads to continue.  Callable
				// from real-time and thread levels ONLY.

    ulong32 getCounter() const;	// Return the count of recursive locks held.

#ifdef Sthread_DEBUG
    Sthread *locker() const;	// Returns pointer to thread holding
				// this lock if known, or NULL if lock
				// not held or the locker is not known
#endif

    boolean_t assertLocked() const;
    				// return FALSE if the mutex is known
				// to be unlocked.  return TRUE if the
				// mutex is locked or if the lock
				// state is not known.

    boolean_t assertUnlocked() const;
    				// return FALSE if the mutex is known
				// to be locked.  return TRUE if the
				// mutex is not locked or if the lock
				// state is not known.
};

/* special faster version used ONLY by internal kernel components.
 * It is faster because we don't record a timestamp of the 
 * interrupt disable and enable operations.
 *
 * This version of SplHigh must NOT be used outside the kernel component.
 */
class Sthread_MutexSplHigh_unconstructed_notimestamp {
protected:
    Spinlock_unconstructed spl;  // must be first for lockstats
    int      ipl;
#ifdef Sthread_DEBUG
    int	     data;
    Sthread  *owner;
	ulong64  ticks_SplStart;
#endif
public:
#ifdef Sthread_DEBUG
    void initialize() { ipl = 0; spl.initialize(); data = 0; owner = (Sthread*)NULL; ticks_SplStart = 0; }
#else
    void initialize() { ipl = 0; spl.initialize(); }
#endif
    void destroy() { assertUnlocked(); spl.destroy(); }

    void lock();                // Lock the Mutex, delaying the thread if
                                // necessary.  Callable from real-time and
                                // thread levels ONLY.

    void lockSlow();		// Lock the Mutex, delaying the processor if
				// necessary.  Callable from any level.  Due
				// to perfomance implications, this lock
				// should NOT be used unless it can not be
				// determined what level you are running at
				// (e.g. printf services)

    void unlock();              // Unlock the Mutex, allowing any blocked
                                // threads to continue.  Callable from
                                // real-time and thread levels ONLY.

    void unlockSlow();		// Unlock the Mutex, allowing any blocked
				// threads to continue.  Callable only to
				// undo a mathing lockSlow.  Due to
				// performance implications these calls
				// should NOT be used unless it can not be
				// determined what level you are running at
				// (e.g. printf services)

    void unlockHigh();          // Unlock the Mutex, allowing any blocked
                                // threads to continue, callable from
                                // interrupt level ONLY

    boolean_t tryLock();        // Grab the lock if it is available.  Return
                                // TRUE if the lock was grabbed, FALSE
                                // otherwise.  This primitive will not
                                // block. Callable from real-time and thread
                                // levels ONLY.

    void lockHigh();            // Lock the Mutex.
                                // callable from interrupt level ONLY

    boolean_t tryLockHigh();    // Grab the lock if it is available.  Return
                                // TRUE if the lock was grabbed, FALSE
                                // otherwise.  This primitive will not block
                                // callable from interrupt level ONLY

#ifdef Sthread_DEBUG
    Sthread *locker() const;	// Returns pointer to thread holding
				// this lock if known, or NULL if lock
				// not held or the locker is not known
#endif

    boolean_t assertLocked() const;
    				// return FALSE if the mutex is known
				// to be unlocked.  return TRUE if the
				// mutex is locked or if the lock
				// state is not known.

    boolean_t assertUnlocked() const;
    				// return FALSE if the mutex is known
				// to be locked.  return TRUE if the
				// mutex is not locked or if the lock
				// state is not known.

#ifdef Sthread_DEBUG
	boolean_t MutexSplHighHoldingTimeReasonable(ulong64 msHoldingTimeLimit);
#endif
};

class Sthread_MutexSplHigh_unconstructed : public Sthread_MutexSplHigh_unconstructed_notimestamp {
private:
#ifdef RECORD_INTR_ON_OFF
    // record timestamps for interrupt on and off - AR 139117
    ulong64 intr_on_ticks;
    ulong64 intr_off_ticks;
#endif
public:
#ifdef Sthread_DEBUG
    void initialize() { Sthread_MutexSplHigh_unconstructed_notimestamp::initialize(); }
#else
    void initialize() { 
                  Sthread_MutexSplHigh_unconstructed_notimestamp::initialize(); 
#ifdef RECORD_INTR_ON_OFF
                  intr_on_ticks = 0 ; 
                  intr_off_ticks = 0;
#endif
                  }
#endif

    void destroy() {}

    // Only the following routines are re-defined by this class.
    // The rest are inherited from the _notimestamp version.
    // In each of the routines below, we record a timestamp whenever
    // interrupts are turned on or off.

    void lock();              // Lock the Mutex, delaying the thread if
                              // necessary.  Callable from real-time and
                              // thread levels ONLY.

    void lockSlow();          // Lock the Mutex, delaying the processor if
                              // necessary.  Callable from any level.  Due
                              // to perfomance implications, this lock
                              // should NOT be used unless it can not be
                              // determined what level you are running at
                              // (e.g. printf services)

    void unlock();            // Unlock the Mutex, allowing any blocked
                              // threads to continue.  Callable from
                              // real-time and thread levels ONLY.

    void unlockSlow();        // Unlock the Mutex, allowing any blocked
                              // threads to continue.  Callable only to
                              // undo a mathing lockSlow.  Due to
                              // performance implications these calls
                              // should NOT be used unless it can not be
                              // determined what level you are running at
                              // (e.g. printf services)

    boolean_t tryLock();      // Grab the lock if it is available.  Return
                              // TRUE if the lock was grabbed, FALSE
                              // otherwise.  This primitive will not
                              // block. Callable from real-time and thread
                              // levels ONLY.
};

class Sthread_MutexSplHigh_notimestamp : 
      public Sthread_MutexSplHigh_unconstructed_notimestamp {
private:
	void initialize();
public:
    Sthread_MutexSplHigh_notimestamp() { Sthread_MutexSplHigh_unconstructed_notimestamp::initialize(); }

};

class Sthread_MutexSplHigh : public Sthread_MutexSplHigh_unconstructed {
private:
    void initialize();
public:
    Sthread_MutexSplHigh() {
        Sthread_MutexSplHigh_unconstructed::initialize();
 	}
};

#define Sthread_MutexHigh Sthread_MutexSplHigh 
#define Sthread_MutexHigh_unconstructed Sthread_MutexSplHigh_unconstructed

struct NTLock
{
    Spinlock_r lock CACHE_ALIGN;
};


class Sthread_MutexRT_unconstructed {
  // 
  // N.B. Most folks use the Sthread_MutexRT derived class (see below).
  // The _unconstructed version is for use ONLY when it is necessary to
  // create a MutexRT before static constructors are called (say in the
  // malloc code).
  //
  //
  // Sthread_MutexRT:	This mutex protects data that can be accessed at
  //			thread or Real-Time levels ONLY.
  //
  //			MutexRT locks may be nested.
  //
  //			Plain Mutexes may be grabbed while a MutexRT is held
  //			through the use of tryLock(), but the caller
  //			should expect that the Mutex will not be available and
  //			may not	spin waiting for it.  This feature may be
  //			used to allow fast path code to handle some requests,
  //			while deferring others to thread level.
  //
  //			For for uniprocessor systems, lock() and tryLock()
  //			always succeed immediately.  For multiprocessor
  //			systems, lock() will spin until another processor
  //			releases the Mutex.
  //
  friend int Sthread_MutexRT_SpinLocker(void);
  friend int Sthread_MutexNT_SpinLocker(ulong32);
  friend class Sthread;
private:
    static Sthread_MutexStats stats;

    static Spinlock_r RTSpinLock;
    static struct NTLock NTSpinLocks[MAX_NBR_NTHREADS];
#ifdef Sthread_DEBUG
    int     data;
    Sthread *owner;
#endif
public:
    static inline void getRTSpinLock() { RTSpinLock.lock_r(); }
    static inline void relRTSpinLock() { RTSpinLock.unlock_r(); }
    static inline void getNTSpinLock(ulong32 NTindex) 
                         { NTSpinLocks[NTindex].lock.lock_r(); }
    static inline void relNTSpinLock(ulong32 NTindex) 
                         { NTSpinLocks[NTindex].lock.unlock_r(); }
    static inline ulong32 tryRTSpinLock() {
#ifdef Blackbird_Schedule
      if (!can_run_rt[processor()])
	return 0;
#endif
      return (RTSpinLock.trylock_r());
    }
    static inline ulong32 try1stRTSpinLock() {
#ifdef Blackbird_Schedule
      if (!can_run_rt[processor()])
	return 0;
#endif
      return (RTSpinLock.try1stlock_r());
    }
    static inline ulong32 try1stNTSpinLock(long32 NTindex) {
#ifdef Blackbird_Schedule
      if (!can_run_rt[processor()]) // TBD: NOT SURE ABOUT THIS
	return 0;
#endif
      return (NTSpinLocks[NTindex].lock.try1stlock_r());
    }
#ifdef Sthread_DEBUG
    void initialize() { data = 0; owner = (Sthread*)NULL; }
#else
    void initialize() { }
#endif
				// Initialize a Mutex.  Useful for boot code
				// that must run before static constructors
				// are called.  Also can be used to reset a
				// Mutex, though this should not be done in
				// production code as it indicates a failure
				// to follow proper locking protocol.

    void destroy() { }          // Destroy a Mutex.

#ifdef Sthread_DEBUG
    Sthread *locker() const;	// Returns pointer to thread holding this
				// lock if known, or NULL if lock not held
				// or the locker is not known
#endif

    boolean_t assertLocked() const;
				// return FALSE if the mutex is known to be
				// unlocked.  return TRUE if the mutex is
				// locked or if the lock state is not known.

    boolean_t assertUnlocked() const;
				// return FALSE if the mutex is known to be
				// locked.  return TRUE if the mutex is not
				// locked or if the lock state is not known.

    void lock(long32 NTindex = -1);  // Lock the Mutex, delaying the thread if
				// necessary.  Callable from real-time and
				// thread levels ONLY.

    void unlock(long32 NTindex = -1);  // Unlock the Mutex, allowing any blocked
				// threads to continue.  Callable from
				// real-time and thread levels ONLY.

    void unlockHigh();		// Unlock the Mutex, allowing any blocked
				// threads to continue, callable from
				// interrupt level ONLY

    boolean_t tryLock();	// Grab the lock if it is available.  Return
				// TRUE if the lock was grabbed, FALSE
				// otherwise.  This primitive will not
				// block. Callable from real-time and thread
				// levels ONLY.

    boolean_t tryLockHigh();	// Grab the lock if it is available.  Return
				// TRUE if the lock was grabbed, FALSE
				// otherwise.  This primitive will not block
				// callable from interrupt level ONLY
};


class Sthread_MutexRT : public Sthread_MutexRT_unconstructed {
private:
	void initialize();
	void destroy();
	
  // 
  // N.B. Most folks use the this version.  The _unconstructed version is
  // for use ONLY when it is necessary to create a MutexRT before static
  // constructors are called (say in the malloc code).
  // Or in cases where explicit control of initialization and
  // destruction of the object is necessary.
  //
public:
    Sthread_MutexRT() { Sthread_MutexRT_unconstructed::initialize(); }
    ~Sthread_MutexRT() { Sthread_MutexRT_unconstructed::destroy(); }
};

class Sthread_MutexProc_unconstructed {
private:
#ifdef Sthread_DEBUG
    ulong32 data;		// bit list of proc holding this mutex
#endif
public:
#ifdef Sthread_DEBUG
    void initialize() { data = 0; }
#else
    void initialize() { }
#endif
    void lock();                // Lock the Mutex, delaying the thread if
                                // necessary.  Callable from real-time and
                                // thread levels ONLY.

    void unlock();              // Unlock the Mutex, allowing any blocked
                                // threads to continue.  Callable from
                                // real-time and thread levels ONLY.

    void unlockHigh();          // Unlock the Mutex, allowing any blocked
                                // threads to continue, callable from
                                // interrupt level ONLY

    boolean_t tryLock();        // Grab the lock if it is available.  Return
                                // TRUE if the lock was grabbed, FALSE
                                // otherwise.  This primitive will not
                                // block. Callable from real-time and thread
                                // levels ONLY.

    boolean_t tryLockHigh();    // Grab the lock if it is available.  Return
                                // TRUE if the lock was grabbed, FALSE
                                // otherwise.  This primitive will not block
                                // callable from interrupt level ONLY
};

class Sthread_MutexProc : public Sthread_MutexProc_unconstructed {
private:
	void initialize();
public:
    Sthread_MutexProc() { Sthread_MutexProc_unconstructed::initialize(); }

};

#ifndef _DQUEUE_HXX_
#include <dqueue.hxx>
#endif




class Sthread_Mutex_unconstructed {
  // 
  // N.B. Most folks use the Sthread_Mutex derived class (see below).
  // The _unconstructed version is for use ONLY when it is necessary to
  // create a Mutex before static constructors are called (say in the
  // device configuration code).
  //
  //
  // Sthread_Mutex:	This mutex protects data that can be accessed at
  //			thread level ONLY.
  //
  //			It should be used for objects that can be locked for
  //			significant periods of time (e.g. waiting for an
  //			external event).
  //
  //			Mutex locks may be nested.
  //
  //			For lock(), the current thread will be suspended if
  //			the Mutex is not available.  As such, lock() is not
  //			usable from real-time or interrupt level, use
  //			tryLock() or tryLockHigh().
  //
  friend class Sthread_Condition_unconstructed;
private:
    static Sthread_MutexStats stats;

    // the lock. If zero it is unlocked. If one it is locked.
    volatile ulong32 Lock;  // must be first for lockstats
    // thread that currently has the lock
    Sthread *lockerPtr;
    // a lock that protects the queue of waiters
    Sthread_MutexSplHigh_unconstructed_notimestamp queueLock;
    // the queue of waiters for this lock
    DQueueHead_unconstructed<Sthread> queue;
    // Called when we fail to get the lock and need to 
    //     queue the thread
    void lockSolid(pointer_value);

    // Called to schedule a waiting thread
    void unlockSolid();
    void unlockSolidHigh();
 public:
    void initialize() { queue.initialize();
			lockerPtr = 0;
                        Lock = 0;
			queueLock.initialize(); }
				// Initialize a Mutex.  Useful for boot code
				// that must run before static constructors
				// are called.  Also can be used to reset a
				// Mutex, though this should not be done in
				// production code as it indicates a failure
				// to follow proper locking protocol.

    void destroy() {
                    assertUnlocked();
                    queueLock.destroy();
                    queue.destroy();
                   }

    Sthread *locker() const { return lockerPtr; }
				// Returns pointer to thread holding this lock, 
				// or NULL if lock not held.

    boolean_t assertLocked() const { return lockerPtr != 0; }
    				// return FALSE if the mutex is known to be unlocked.  
				// return TRUE if the mutex is locked.

    boolean_t assertUnlocked() const { return lockerPtr == 0; }
				// return FALSE if the mutex is known to be locked.  
				// return TRUE if the mutex is not locked.

    void lock();		// Lock the Mutex, delaying the thread if
				// necessary.  Callable from thread level
				// ONLY

    void unlock();		// Unlock the Mutex, allowing any blocked
				// threads to continue.  Callable from
				// real-time and thread levels ONLY

    void unlockHigh();		// Unlock the Mutex, allowing any blocked
				// threads to continue, callable from
				// interrupt level ONLY

    void unlockVeryHigh();      // KERNEL USE ONLY	

    boolean_t tryLock();	// Grab the lock if it is available.  Return
				// TRUE if the lock was grabbed, FALSE
				// otherwise.  This primitive will not block
				// and can be used at any level on any Mutex
				// variety.  Callable from real-time and
				// thread levels ONLY.

    boolean_t tryLockHigh();	// Grab the lock if it is available.  Return
				// TRUE if the lock was grabbed, FALSE
				// otherwise.  This primitive will not block
				// and can be used at any level on any Mutex
				// variety.  callable from interrupt level
				// ONLY
};

class Sthread_Mutex : public Sthread_Mutex_unconstructed {
private:
//	void initialize(); HASSEY temp workaround for Rhea build issue
  // 
  // N.B. Most folks use the this version.  The _unconstructed version is
  // for use ONLY when it is necessary to create a Mutex before static
  // constructors are called (say in the malloc code).
  //
public:
    Sthread_Mutex() { 
        Sthread_Mutex_unconstructed::initialize();
    }
};


class Sthread_Condition_unconstructed {
    //
    // Condition that can be waited for.
    //
    friend void Sthread_conditionUnlock_internal
	(Sthread_Mutex_unconstructed* m,
	 Sthread_Condition_unconstructed* c);

    friend void Sthread_conditionUnlockSpl_internal
	(Sthread_MutexSpl_unconstructed* m,
	 Sthread_Condition_unconstructed* c);

    friend void Sthread_conditionUnlockRT_internal
	(Sthread_MutexRT_unconstructed* m,
	 Sthread_Condition_unconstructed* c);

    friend void	Sthread_conditionUnlockSplHigh_internal
	(Sthread_MutexSplHigh_unconstructed_notimestamp* m,
	 Sthread_Condition_unconstructed* c);
 
    friend class RWlockRT;
protected:
    Sthread_MutexSplHigh_unconstructed_notimestamp queueLock;
    DQueueHead_unconstructed<Sthread> queue;
public:
    void initialize();
    void destroy() {}
    
    //
    // Return true if any thread is waiting on this condition
    //
    boolean_t isWaiting();
    
    //
    // Wake up at least one thread that is waiting on this condition.
    // Due to a rare race condition, it is possible for more than one
    // thread to be awakened.  Application code must be prepared to
    // handle this case.
    //
    void signal();
    void signalHigh();
    
    //
    // Wake up all threads currently waiting on this condition.
    //
    void broadcast();
    void broadcast_high();
    
    //
    // Atomically release a Mutex and wait on the condition.  When the
    // wakeup happens, the Mutex will be re-aquired.
    //
    //
    // Note: overloading is used in lieu of inheritance for efficiency.
    //       This avoids the costs of virtual functions and allows mutex
    //       and condition variables to be used early in the boot cycle
    //       (where constructors can't be called to set up the vtable
    //       pointers).
    //
    void wait(Sthread_Mutex_unconstructed* m);
    void wait(Sthread_MutexSpl_unconstructed* m);
    void wait(Sthread_MutexRT_unconstructed* m);
    void wait(Sthread_MutexSplHigh_unconstructed_notimestamp* m);
};

class Sthread_Condition : public Sthread_Condition_unconstructed {
private:
//	void initialize(); HASSEY temp workaround for Rhea build issue
  public:
    Sthread_Condition();
    ~Sthread_Condition();
};

class Sthread_ConditionLight : public Sthread_Condition_unconstructed {
private:
//	void initialize(); HASSEY temp workaround for Rhea build issue
  public:
    Sthread_ConditionLight();
    ~Sthread_ConditionLight();
};

#include <m_lock.hxx>


//
// Implementation of inline functions for Sthread_Condition
//

inline void Sthread_Condition_unconstructed::initialize()
{
    queueLock.initialize();
    queue.initialize();
}
    
inline boolean_t Sthread_Condition_unconstructed::isWaiting()
{
    return !queue.is_empty();
}
    
inline Sthread_Condition::Sthread_Condition()
{
    Sthread_Condition_unconstructed::initialize();
}

inline Sthread_ConditionLight::Sthread_ConditionLight()
{
    Sthread_Condition_unconstructed::initialize();
}

#endif // Sthread_INLINE

#endif /* __SADE__ */

#endif // _SLOCK_HXX_
